package com.ccteam.fluidmusic.ui.moment

import androidx.lifecycle.*
import androidx.paging.LoadState
import androidx.paging.cachedIn
import com.ccteam.fluidmusic.utils.Event
import com.ccteam.fluidmusic.utils.cancelIfActive
import com.ccteam.fluidmusic.utils.setValueIfNew
import com.ccteam.fluidmusic.view.bean.ErrorMessage
import com.ccteam.fluidmusic.view.bean.LoadMessage
import com.ccteam.model.Resource
import com.ccteam.network.ApiError
import com.ccteam.shared.core.UserCore
import com.ccteam.shared.domain.moment.DeleteMomentDataUseCase
import com.ccteam.shared.domain.moment.MomentDetailDataUseCase
import com.ccteam.shared.domain.moment.comment.MomentDetailCommentDataUseCase
import com.ccteam.shared.domain.moment.up.CheckMomentUpDataUseCase
import com.ccteam.shared.domain.moment.up.PublishMomentUpDataUseCase
import com.ccteam.shared.result.moment.MomentListItem
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import javax.inject.Inject
import kotlin.math.max
import kotlin.math.min

/**
 * @author Xiaoc
 * @since 2021/3/25
 *
 * 朋友圈详情ViewModel层
 */
@HiltViewModel
class MomentDetailViewModel @Inject constructor(
    private val deleteMomentDataUseCase: DeleteMomentDataUseCase,
    private val momentDetailDataUseCase: MomentDetailDataUseCase,
    momentDetailCommentDataUseCase: MomentDetailCommentDataUseCase,
    private val publishMomentUpDataUseCase: PublishMomentUpDataUseCase,
    private val checkMomentUpDataUseCase: CheckMomentUpDataUseCase,
    private val userCore: UserCore,
    savedStateHandle: SavedStateHandle
): ViewModel() {

    private val momentDetailResult = MutableLiveData<Resource<List<MomentListItem>>>(Resource.Loading())

    private val momentId = MutableLiveData<String>()

    private val _momentDetail = MediatorLiveData<List<MomentListItem>>()
    val momentDetail: LiveData<List<MomentListItem>> get() = _momentDetail

    private val _shouldRefreshComment = MutableLiveData<Event<Boolean>>()
    val shouldRefreshComment: LiveData<Event<Boolean>> get() = _shouldRefreshComment

    /**
     * 点赞加载信息
     */
    private val _upLoadMessage = MutableLiveData<Event<LoadMessage>>()
    val upLoadMessage: LiveData<Event<LoadMessage>> get() = _upLoadMessage

    /**
     * 是否点赞
     */
    private val _upInfo = MutableLiveData(MomentUpData(false,0))
    val upInfo: LiveData<MomentUpData> get() = _upInfo

    private val _isLogin = MutableLiveData(false)
    val isLogin: LiveData<Boolean> get() = _isLogin

    private val _loadMessage = MediatorLiveData<LoadMessage>()
    val loadMessage: LiveData<LoadMessage> get() = _loadMessage

    private val _canDelete = MutableLiveData(false)
    val canDelete: LiveData<Boolean> get() = _canDelete

    private val _deleteLoadMessage = MutableLiveData<Event<LoadMessage>>()
    val deleteLoadMessage: LiveData<Event<LoadMessage>> get() = _deleteLoadMessage

    private val momentLoadMessage = momentDetailResult.map {
        when(it){
            is Resource.Success ->{
                if(it.data.isNullOrEmpty()){
                    LoadMessage.Error(ErrorMessage("内容为空",ApiError.unknownCode))
                } else {
                    LoadMessage.NotLoading
                }
            }
            is Resource.Loading ->{
                LoadMessage.Loading
            }
            is Resource.Error ->{
                LoadMessage.Error(ErrorMessage(it.message,it.errorCode))
            }
        }
    }
    private val commentLoadMessage = MutableLiveData<LoadMessage>()

    private var loginJob: Job? = null
    init {
        _momentDetail.addSource(momentId){
            refreshMomentDetail()
        }

        momentId.setValueIfNew(savedStateHandle["momentId"])

        _loadMessage.addSource(momentLoadMessage){
            _loadMessage.value = checkLoadMessage(it,commentLoadMessage.value)
        }
        _loadMessage.addSource(commentLoadMessage){
            _loadMessage.value = checkLoadMessage(it,momentLoadMessage.value)
        }

        loginJob = viewModelScope.launch {
            userCore.isLogin.collectLatest {
                _isLogin.value = it
            }
        }
    }

    val commentList = momentDetailCommentDataUseCase(momentId.value)
        .cachedIn(viewModelScope)

    fun refreshMomentDetail(){
        momentId.value?.let { momentId ->
            viewModelScope.launch {
                momentDetailDataUseCase(momentId).collectLatest {
                    momentDetailResult.value = it

                    if(it is Resource.Success){
                        _momentDetail.value = it.data ?: emptyList()

                        if(!it.data.isNullOrEmpty()){
                            _upInfo.value = MomentUpData(false, it.data!![0].upNum)

                            // 检查该帖子是不是当前登陆者发布的，如果是则显示删除按钮
                            _canDelete.value = it.data!![0].userId == userCore.userInfo.value.userId
                        }

                        // 检查朋友圈点赞情况
                        _upLoadMessage.value = Event(LoadMessage.Loading)
                        val result = checkMomentUpDataUseCase(momentId)
                        if(result is Resource.Success){
                            _upInfo.value = _upInfo.value?.copy(isUp = result.data ?: false)
                        }
                        // 在第一次进入时加载的点赞信息，不需要显示加载错误失败的信息
                        _upLoadMessage.value = Event(LoadMessage.NotLoading)
                    }
                }
            }
        }
    }

    fun refreshCommentDetail(){
        _shouldRefreshComment.value = Event(true)
    }

    fun setLoadMessage(states: LoadState){
        when (states) {
            is LoadState.Loading -> {
                commentLoadMessage.value = LoadMessage.Loading
            }
            is LoadState.Error -> {
                commentLoadMessage.value = LoadMessage.Error(ErrorMessage(states.error.message,ApiError.unknownCode))
            }
            else -> {
                commentLoadMessage.value = LoadMessage.NotLoading
            }
        }
    }

    /**
     * 进行朋友圈点赞
     */
    fun setMomentUp(){
        if(_upLoadMessage.value?.peekContent() == LoadMessage.Loading){
            return
        }

        momentId.value?.let {
            viewModelScope.launch {
                addMomentUp()

                _upLoadMessage.value = Event(LoadMessage.Loading)
                val result = publishMomentUpDataUseCase(Pair(true,it))
                if(result !is Resource.Success){
                    _upLoadMessage.value = Event(LoadMessage.Error(ErrorMessage(result.message,result.errorCode)))
                    resumeMomentUp()
                } else {
                    _upLoadMessage.value = Event(LoadMessage.NotLoading)
                }
            }
        }
    }

    /**
     * 取消朋友圈点赞
     */
    fun cancelMomentUp(){
        if(_upLoadMessage.value?.peekContent() == LoadMessage.Loading){
            return
        }

        momentId.value?.let {
            viewModelScope.launch {
                resumeMomentUp()

                _upLoadMessage.value = Event(LoadMessage.Loading)
                val result = publishMomentUpDataUseCase(Pair(false,it))
                if(result !is Resource.Success){
                    _upLoadMessage.value = Event(LoadMessage.Error(ErrorMessage(result.message,result.errorCode)))
                    addMomentUp()
                } else {
                    _upLoadMessage.value = Event(LoadMessage.NotLoading)
                }
            }
        }
    }

    fun deleteMoment(){
        momentId.value?.let {
            viewModelScope.launch {
                _deleteLoadMessage.value = Event(LoadMessage.Loading)

                val result = deleteMomentDataUseCase(it)
                if(result is Resource.Success){
                    _deleteLoadMessage.value = Event(LoadMessage.Success)
                } else {
                    _deleteLoadMessage.value = Event(LoadMessage.Error(ErrorMessage(result.message,result.errorCode)))
                }
            }
        }

    }

    private fun checkLoadMessage(selfLoadMessage: LoadMessage?,otherLoadMessage: LoadMessage?): LoadMessage{
        return when{
            selfLoadMessage is LoadMessage.Loading || otherLoadMessage is LoadMessage.Loading ->{
                LoadMessage.Loading
            }
            selfLoadMessage is LoadMessage.Error ->{
                LoadMessage.Error(ErrorMessage(selfLoadMessage.errorMessage.description,selfLoadMessage.errorMessage.errorCode))
            }
            otherLoadMessage is LoadMessage.Error ->{
                LoadMessage.Error(ErrorMessage(otherLoadMessage.errorMessage.description,otherLoadMessage.errorMessage.errorCode))
            }
            selfLoadMessage is LoadMessage.NotLoading && otherLoadMessage is LoadMessage.NotLoading ->{
                LoadMessage.NotLoading
            }
            else ->{
                LoadMessage.Error(ErrorMessage())
            }
        }
    }

    private fun addMomentUp(){
        var newUpNum = _upInfo.value?.upNum ?: 0
        _upInfo.value = MomentUpData(true,++newUpNum)
    }

    private fun resumeMomentUp(){
        var newUpNum = _upInfo.value?.upNum ?: 0
        _upInfo.value = MomentUpData(false, max(--newUpNum,0))
    }

    data class MomentUpData(
        val isUp: Boolean,
        val upNum: Int
    )

    override fun onCleared() {
        super.onCleared()

        loginJob.cancelIfActive()
    }
}